package com.hj.dapp.business.budget.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hj.dapp.business.budget.mapper.BudgetMapper;
import com.hj.dapp.business.budget.mapper.BudgetProjectMapper;
import com.hj.dapp.business.budget.model.*;
import com.hj.dapp.business.budget.service.BudgetItemService;
import com.hj.dapp.business.budget.service.BudgetService;
import com.hj.dapp.business.budget.vo.BudgetBindListVO;
import com.hj.dapp.business.budget.vo.BudgetPageVO;
import com.hj.dapp.business.budget.vo.BudgetProjectSave;
import com.hj.dapp.business.budget.vo.BudgetSaveVO;
import com.hj.dapp.business.craft.model.Craft;
import com.hj.dapp.business.customer.model.IntendedCustomer;
import com.hj.dapp.business.customer.service.IntendedCustomerService;
import com.hj.dapp.business.engineer.model.EngineerProject;
import com.hj.dapp.business.engineer.service.EngineerProjectService;
import com.hj.dapp.business.project.model.Project;
import com.hj.dapp.business.user.model.User;
import com.hj.dapp.business.user.service.UserService;
import com.hj.dapp.common.request.PageRequest;
import com.hj.dapp.common.util.ExpUtil;
import com.hj.dapp.common.util.NumStrConvertor;
import org.jxls.common.Context;
import org.jxls.util.JxlsHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.servlet.ServletOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.hj.dapp.common.constant.CustomerConstant.PROJECT_OTHER_ID;
import static com.hj.dapp.common.constant.LightAuxiliaryConstant.NORMAL_FEE;
import static com.hj.dapp.common.constant.LightAuxiliaryConstant.RATE_FEE;
import static com.hj.dapp.config.exp.BusinessErrorEnum.*;

/**
 * @author 胡奥程
 * @version 1.0
 * @date 2024/1/19
 */
@Service
public class BudgetServiceImpl implements BudgetService {
    @Autowired
    private BudgetItemService budgetItemService;
    @Autowired
    private BudgetMapper budgetMapper;
    @Autowired
    private IntendedCustomerService intendedCustomerService;
    @Autowired
    private EngineerProjectService engineerProjectService;
    @Autowired
    private UserService userService;

    @Autowired
    private BudgetProjectMapper budgetProjectMapper;

    public BudgetExportVO calcDirectPrice(Long customerId, Long engineerProjectId) {
        BudgetExportVO budget = budgetMapper.exportLightAuxiliary(customerId, engineerProjectId);
        budget.getCrafts().forEach(n -> {
            AtomicReference<Integer> init = new AtomicReference<>(1);
            //计算序号
            n.getBudgetUnits().forEach(budgetUnit -> {
                budgetUnit.setSeq(init.getAndSet(init.get() + 1));
            });
            //计算价格小计
            if (!PROJECT_OTHER_ID.equals(n.getId())) {
                BigDecimal totalPrice = n.getBudgetUnits().stream().map(BudgetUnit::getTotalPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                n.setTotalPrice(totalPrice);
            }
        });
        //计算工程直接价款
        BigDecimal projectPrice = budget.getCrafts().stream()
                .filter(n -> !PROJECT_OTHER_ID.equals(n.getId()))
                .map(BudgetExportItemVO::getTotalPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        budget.setDirectPrice(projectPrice);
        return budget;
    }

    @Override
    public void exportLightAuxiliary(Long customerId, Long engineerProjectId, ServletOutputStream outputStream) {
        //计算直接价款
        BudgetExportVO budget = calcDirectPrice(customerId, engineerProjectId);
        //计算其他项目
        List<BudgetExportItemVO> collect = budget.getCrafts().stream().filter(n -> PROJECT_OTHER_ID.equals(n.getId())).collect(Collectors.toList());
        if (ObjectUtils.isEmpty(collect)) {
            ExpUtil.throwExp(DOWN_REJECT);
        }
        BudgetExportItemVO budgetExportItemVO = collect.get(0);
        BigDecimal otherTotalPrice = BigDecimal.ZERO;

        List<BudgetUnit> rateList = new ArrayList<>();
        List<BudgetUnit> normalList = new ArrayList<>();
        Integer seq = 1;
        for (BudgetUnit unit : budgetExportItemVO.getBudgetUnits()) {
            if (RATE_FEE.equals(unit.getBillingMethod())) {
                BigDecimal tempResult = budget.getDirectPrice().multiply(unit.getRate());
                unit.setTotalPrice(tempResult);
                rateList.add(unit);
                otherTotalPrice = otherTotalPrice.add(tempResult);
            } else {
                otherTotalPrice = otherTotalPrice.add(unit.getTotalPrice());
                normalList.add(unit);
            }
        }
        for (BudgetUnit budgetUnit : rateList) {
            budgetUnit.setSeq(seq++);
        }
        for (BudgetUnit budgetUnit : normalList) {
            budgetUnit.setSeq(seq++);
        }
        budgetExportItemVO.setTotalPrice(otherTotalPrice);
        //计算最终价款
        budget.setFinalPrice(budgetExportItemVO.getTotalPrice().add(budget.getDirectPrice()));
        //计算折扣率
        EngineerProject engineerProject = engineerProjectService.get(budget.getEngineerProjectId());
        budget.setDiscountPrice(budget.getFinalPrice().multiply(engineerProject.getDiscountRate()));
        //过滤掉其他项目
        budget.setCrafts(budget.getCrafts().stream()
                .filter(n -> !PROJECT_OTHER_ID.equals(n.getId()))
                .collect(Collectors.toList()));

        //处理中文序号
        Integer capNumber = 1;
        for (BudgetExportItemVO craft : budget.getCrafts()) {
            craft.setName(NumStrConvertor.cnNumConvertor(capNumber++) + "、" + craft.getName());
        }
        InputStream is = null;
        try {
            ClassLoader loader = this.getClass().getClassLoader();
            is = loader.getResourceAsStream("classpath:template-q.xlsx");
            if (ObjectUtils.isEmpty(is)) {
                ClassPathResource classPathResource = new ClassPathResource("template-q.xlsx");
                is = classPathResource.getInputStream();
            }
            Context context = new Context();
            context.putVar("budget", budget);
            context.putVar("other", budgetExportItemVO);
            context.putVar("rateList", rateList);
            context.putVar("normalList", normalList);
            JxlsHelper.getInstance().processTemplate(is, outputStream, context);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public Budget saveBudgetPrimary(Long customerId, Long engineerProjectId) {
        Budget budget = new Budget();
        //客户
        budget.setCustomerId(customerId);
        IntendedCustomer intendedCustomer = intendedCustomerService.get(customerId);
        budget.setCustomerName(intendedCustomer.getName());
        budget.setCustomerPhone(intendedCustomer.getPhone());
        //工程地址
        budget.setEngineerProjectId(engineerProjectId);
        EngineerProject engineerProject = engineerProjectService.get(engineerProjectId);
        budget.setEngineerName(engineerProject.getAddress());
        budget.setEngineerAddress(engineerProject.getAddress());
        //设计师
        budget.setDesignerId(intendedCustomer.getDesignerId());
        User user = userService.getUserById(intendedCustomer.getDesignerId());
        budget.setDesignerName(user.getRealName());
        budget.setDesignerPhone(user.getPhone());
        budget.setDesignerId(user.getId());
        //预算审核
        budget.setReviewerId(intendedCustomer.getReviewerId());
        User reviewer = userService.getUserById(intendedCustomer.getReviewerId());
        budget.setReviewerName(reviewer.getRealName());
        //派工经理
        budget.setSupervisorId(intendedCustomer.getSupervisorId());
        User supervisor = userService.getUserById(intendedCustomer.getSupervisorId());
        budget.setSupervisorName(supervisor.getRealName());
        budgetMapper.insert(budget);
        return budget;
    }

    @Override
    public void save(BudgetSaveVO budgetSaveVO) {
        QueryWrapper<Budget> wrapper = new QueryWrapper();
        wrapper.eq("customer_id", budgetSaveVO.getCustomerId());
        wrapper.eq("engineer_project_id", budgetSaveVO.getEngineerProjectId());
        Budget budget = budgetMapper.selectOne(wrapper);
        //如果轻辅预算主表不存在，创建主表
        if (ObjectUtils.isEmpty(budget)) {
            saveBudgetPrimary(budgetSaveVO.getCustomerId(), budgetSaveVO.getEngineerProjectId());

        } else {
            //清空历史数据，重新建立绑定
            budgetItemService.deleteRel(budget.getId(), budgetSaveVO.getProjectId());
        }
        Budget finalBudget = budget;

        budgetSaveVO.getCrafts().forEach(n -> {
            BudgetItem budgetItem = new BudgetItem();
            BeanUtils.copyProperties(n, budgetItem);
            //设置工艺ID
            budgetItem.setCraftId(n.getId());
            budgetItem.setId(null);
            //设置项目ID
            budgetItem.setProjectId(budgetSaveVO.getProjectId());
            //设置预算主表ID
            budgetItem.setBudgetId(finalBudget.getId());
            //计算合价
            if (NORMAL_FEE.equals(n.getBillingMethod())) {
                try {
                    budgetItem.setTotalPrice(budgetItem.getSalePrice().multiply(budgetItem.getNum()));
                } catch (Exception e) {
                    ExpUtil.throwExp(NUMBER_REJECT);
                }

            }
            budgetItemService.save(budgetItem);
        });


    }

    @Override
    public IPage<BudgetPageVO> page(PageRequest<Budget> pageRequest, Principal principal) {
        Page<Budget> page = new Page<>();
        page.setSize(pageRequest.getSize());
        page.setCurrent(pageRequest.getCurrent());
        Budget query = pageRequest.getQuery();
        query.setCreateBy(principal.getName());
        return budgetMapper.selectPageVO(page, query);
    }

    @Override
    public List<Craft> listBindCrafts(BudgetBindListVO budget) {

        return budgetMapper.listBindCrafts(budget);
    }

    @Override
    public void saveProjects(BudgetProjectSave budgetProjectSave) {
        QueryWrapper<Budget> wrapper = new QueryWrapper();
        wrapper.eq("customer_id", budgetProjectSave.getCustomerId());
        wrapper.eq("engineer_project_id", budgetProjectSave.getEngineerProjectId());
        Budget budget = budgetMapper.selectOne(wrapper);
        if (ObjectUtils.isEmpty(budget)) {
            //保存预算主表数据
            budget = saveBudgetPrimary(budgetProjectSave.getCustomerId(), budgetProjectSave.getEngineerProjectId());
        } else {
            //删除预算项目关联表关联关系
            QueryWrapper<BudgetProject> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("budget_id", budget.getId());
            budgetProjectMapper.delete(queryWrapper);
            //删除不具备关联的预算项目
            budgetItemService.deleleBindRel(budget.getId(),budgetProjectSave.getProjects());
        }
        //保存预算和项目关联表
        Budget finalBudget = budget;
        budgetProjectSave.getProjects().forEach(n -> {
            BudgetProject budgetProject = new BudgetProject();
            budgetProject.setBudgetId(finalBudget.getId());
            budgetProject.setProjectId(n);
            budgetProjectMapper.insert(budgetProject);
        });

    }

    @Override
    public List<BudgetProject> getBudgetProjects(Long budgetId) {
        QueryWrapper<BudgetProject> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("budget_id", budgetId);
        return budgetProjectMapper.selectList(queryWrapper);
    }

    @Override
    public BudgetExportVO list(Long customerId, Long engineerProjectId) {
        return budgetMapper.exportLightAuxiliary(customerId, engineerProjectId);
    }

    @Override
    public BudgetExportVO getProjects(Long customerId, Long engineerProjectId) {
        QueryWrapper<Budget> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("customer_id", customerId);
        queryWrapper.eq("engineer_project_id", engineerProjectId);
        Budget b = budgetMapper.selectOne(queryWrapper);
        if (ObjectUtils.isEmpty(b)) {
            return new BudgetExportVO();
        }
        //计算直接价款
        BudgetExportVO  budget= calcDirectPrice(customerId, engineerProjectId);
        //计算其他项目
        List<BudgetExportItemVO> collect = budget.getCrafts().stream().filter(n -> PROJECT_OTHER_ID.equals(n.getId())).collect(Collectors.toList());
        if (!ObjectUtils.isEmpty(collect)) {
            BudgetExportItemVO budgetExportItemVO = collect.get(0);
            BigDecimal otherTotalPrice = BigDecimal.ZERO;
            Integer seq = 1;
            for (BudgetUnit unit : budgetExportItemVO.getBudgetUnits()) {
                if (RATE_FEE.equals(unit.getBillingMethod())) {
                    BigDecimal tempResult = budget.getDirectPrice().multiply(unit.getRate());
                    unit.setTotalPrice(tempResult);
                    otherTotalPrice = otherTotalPrice.add(tempResult);
                } else {
                    otherTotalPrice = otherTotalPrice.add(unit.getTotalPrice());
                }
            }
            budgetExportItemVO.setTotalPrice(otherTotalPrice);
            //计算最终价款
            budget.setFinalPrice(budgetExportItemVO.getTotalPrice().add(budget.getDirectPrice()));
        }
        return budget;
    }

    @Override
    public void saveBatch(List<BudgetSaveVO> budgetSaveVOList) {
        budgetSaveVOList.forEach(this::save);

    }

    @Override
    public BigDecimal getDiscountPrice(Long customerId, Long engineerProjectId) {
        BudgetExportVO projects = getProjects(customerId, engineerProjectId);
        BigDecimal finalPrice = projects.getFinalPrice();
        EngineerProject engineerProject = engineerProjectService.get(engineerProjectId);
        if (ObjectUtils.isEmpty(finalPrice)) {
            return BigDecimal.ZERO;
        }
        return finalPrice.multiply(engineerProject.getDiscountRate());
    }
}
